<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="pNTnl" id="pNTnl"><span data-lake-id="u93332a62" id="u93332a62">典型回答</span></h1>
  <p data-lake-id="u5cd229c7" id="u5cd229c7"><br></p>
  <p data-lake-id="u6698c7f7" id="u6698c7f7"><span data-lake-id="uc9eb94ae" id="uc9eb94ae">类型擦除是Java在处理泛型的一种方式，如Java的编译器在编译以下代码时：</span></p>
  <p data-lake-id="u320ac3bb" id="u320ac3bb"><br></p>
  <pre lang="java"><code>
public class Foo&lt;T&gt; {
    T bar;
    void doSth(T param) {
    }
};

Foo&lt;String&gt; f1;
Foo&lt;Integer&gt; f2;
</code></pre>
  <p data-lake-id="ud09027e9" id="ud09027e9"><br></p>
  <p data-lake-id="u6e1f7015" id="u6e1f7015"><span data-lake-id="ua3b5afb5" id="ua3b5afb5">在编译后的字节码文件中，会把泛型的信息擦除掉：</span></p>
  <p data-lake-id="u72652f67" id="u72652f67"><br></p>
  <pre lang="java"><code>
public class Foo {
    Object bar;
    void doSth(Object param) {
    }
};
</code></pre>
  <p data-lake-id="u940ba247" id="u940ba247"><br></p>
  <p data-lake-id="u9a4a8312" id="u9a4a8312"><span data-lake-id="ufb05151a" id="ufb05151a">也就是说，在代码中的Foo&lt;String&gt; 和 Foo&lt;Integer&gt;使用的类，经过编译后都是同一个类。</span></p>
  <p data-lake-id="u0c1bb1f2" id="u0c1bb1f2"><br></p>
  <p data-lake-id="u9d32801f" id="u9d32801f"><span data-lake-id="ud5fc9bcc" id="ud5fc9bcc">所以说泛型技术实际上是Java语言的一颗语法糖，因为泛型经过编译器处理之后就被擦除了。</span></p>
  <p data-lake-id="u821c978c" id="u821c978c"><br></p>
  <p data-lake-id="u586dacc2" id="u586dacc2"><span data-lake-id="u8b8e7be1" id="u8b8e7be1">这种擦除的过程，被称之为——类型擦除。所以类型擦除指的是通过类型参数合并，将泛型类型实例关联到同一份字节码上。编译器只为泛型类型生成一份字节码，并将其实例关联到这份字节码上。类型擦除的关键在于从泛型类型中清除类型参数的相关信息，并且在必要的时候添加类型检查和类型转换的方法。</span></p>
  <p data-lake-id="u4d19c8df" id="u4d19c8df"><br></p>
  <p data-lake-id="u14521c1d" id="u14521c1d"><strong><span data-lake-id="u269edfa0" id="u269edfa0">类型擦除可以简单的理解为将泛型java代码转换为普通java代码，只不过编译器更直接点，将泛型java代码直接转换成普通java字节码。</span></strong></p>
  <p data-lake-id="u1ed084b2" id="u1ed084b2"><span data-lake-id="u24e00d34" id="u24e00d34">​</span><br></p>
  <p data-lake-id="u7768e8b2" id="u7768e8b2"><span data-lake-id="u4dff8d99" id="u4dff8d99">​</span><br></p>
  <h1 data-lake-id="oCkiD" id="oCkiD"><span data-lake-id="u5368f636" id="u5368f636">扩展知识</span></h1>
  <p data-lake-id="u37c23d72" id="u37c23d72"><br></p>
  <h2 data-lake-id="k8AXo" id="k8AXo"><span data-lake-id="u7a5dd035" id="u7a5dd035">C语言对泛型的支持</span></h2>
  <p data-lake-id="u5c306f2b" id="u5c306f2b"><span data-lake-id="u46d3a87a" id="u46d3a87a">泛型是一种编程范式，在不同的语言和编译器中的实现和支持方式都不一样。</span></p>
  <p data-lake-id="uf50c503b" id="uf50c503b"><br></p>
  <p data-lake-id="u730a5284" id="u730a5284"><span data-lake-id="ua82a76a7" id="ua82a76a7">通常情况下，一个编译器处理泛型有多种方式，在C++中，当编译器对以下代码编译时：</span></p>
  <p data-lake-id="ueac274fe" id="ueac274fe"><br></p>
  <pre lang="java"><code>
template&lt;typename T&gt;
struct Foo
{
    T bar;
    void doSth(T param) {
    }
};

Foo&lt;int&gt; f1;
Foo&lt;float&gt; f2;
</code></pre>
  <p data-lake-id="uf6f89b62" id="uf6f89b62"><br></p>
  <p data-lake-id="u780cf7fa" id="u780cf7fa"><span data-lake-id="u963bef61" id="u963bef61">当编译器对其进行编译时，编译器发现要用到Foo&lt;int&gt;和Foo&lt;float&gt;，这时候就会为每一个泛型类新生成一份执行代码。相当于新创建了如下两个类：</span></p>
  <p data-lake-id="u690cacd1" id="u690cacd1"><br></p>
  <pre lang="java"><code>
struct FooInt
{
    int bar;
    void doSth(int param) {
    }
};

struct FooFloat
{
    float bar;
    void doSth(float param) {
    }
};
</code></pre>
  <p data-lake-id="u891c316b" id="u891c316b"><br></p>
  <p data-lake-id="u9a09ac69" id="u9a09ac69"><span data-lake-id="u099b515d" id="u099b515d">这种做法，用起来的时候很方便，只需要根据具体类型找到具体的的类和方法就行了。但是问题是，当我们多次使用不同类型的模板时，就会创建出来的很多新的类，就会导致代码膨胀。</span></p>
 </body>
</html>